package heman.server.entities;

import java.util.*;



public class Table {
	static final int numPlayers=4;
	static final String defaultOptions="turnTime=30,noS=true,maxScore=50";
	String id=null;
	Player moderator=null;
	/*String gameID=null;*/
	ArrayList<Player> playerList=new ArrayList<Player>(); 
	ArrayList<Player> invitationList=new ArrayList<Player>();
	int seed=0;
	String options=defaultOptions;
	String game=null;
	TableType type=TableType.PUBLIC;
	//This records whether the player is still on the table
	Hashtable<Player, Boolean> playersPresent=new Hashtable<Player,Boolean>();
	
	Iterator<Player> iter=null;
	
	public Player getModerator() {
		return moderator;
	}
	public void setModerator(Player moderator) {
		//Check whether we should add the moderator to the player list
		boolean in=false;
		for (Player p:playerList)
			if (p==moderator)
				in=true;
		if (!in)
			playerList.add(moderator);
				
		this.moderator = moderator;
	}
	public String getID(){
		return id;
	}
	public int getSeed() {
		return seed;
	}
	public void setSeed(int seed) {
		this.seed = seed;
	}
	public Table(String id){
		this.id=id;
	}
	public String getOptions() {
		return options;
	}
	public void setOptions(String options) {
		this.options = options;
	}
	public TableType getType() {
		return type;
	}
	public void setType(TableType type) {
		this.type = type;
	}
	public boolean addPlayer(Player p){
		if (p==null) return false;
		synchronized (playerList) {
			//
			if (playerList.size()>=numPlayers || type==TableType.IN_PLAY) return false;
			else return playerList.add(p);
		}
		
		//playersPresent.put(p, new Boolean(true));
	}
	public boolean invitePlayer(Player p){
		if(p==null) return false;
		synchronized (invitationList) {
			if(invitationList.size()+playerList.size()>=numPlayers || type!=TableType.BY_INVITATION) return false;
			else return invitationList.add(p);
		}
	}
	public boolean removeinvitePlayer(Player p){
		synchronized (invitationList) {
			return invitationList.remove(p);
		}
	}
	public ArrayList<String> getPlayerIDs(){
		ArrayList<String> list=new ArrayList<String	>();
		//What if a player is removed from the player list
		//during this function
		synchronized (playerList) {
			for (Player p:playerList)
				list.add(p.getId());
		}
		
		return list;
	}
	public boolean removePlayer(Player p){
		synchronized (playerList) {
			//A player may exit table just before the game start
			//Then it becomes an "exit"
			if (type==TableType.IN_PLAY) exit(p);
			
			return playerList.remove(p);
		}
	}
	
	//Whether is player is really on the table
	//If the player leaves the table before the game finishes, it's NOT on this table any more
	public boolean onTable(Player p){
		if (p==null) return false;
		
		Boolean boolean1=playersPresent.get(p);
		if (boolean1==null) return false;
		else return boolean1;
	}
	public boolean onTable(String pID){
		if (pID==null )return false;
		Enumeration<Player> enumeration=playersPresent.keys();
		for (;enumeration.hasMoreElements();){
			Player p=enumeration.nextElement();
			if (pID.equals(p.getId())) return true;
		}
		
		return false;
	}
	//This returns the player who should take the next turn
	public Player getNextPlayer(){
		if (iter==null)
			//Please call "startGame()"
			return null;
		
		if (iter.hasNext())
			return iter.next();
		else{
			
			iter=playerList.iterator();
			return iter.next();
		}
	}
	public ArrayList<String> getAllPresentPlayerIDs(){
		ArrayList<String> list=new ArrayList<String>();
		synchronized (playerList) {
			for (Player p:playerList)
				if (playersPresent.get(p))
					list.add(p.getId());
		}
		return list;
	}
	/**
	 * Please call this function when game starts to do some extra
	 * initialization of the table before game
	 */
	public boolean startGame(){
		synchronized (playerList) {
			
		
		for (Player p:playerList) {
			//All player are on the table
			playersPresent.put(p, new Boolean(true));
		}
		this.type=TableType.IN_PLAY;
		iter=playerList.iterator();
		}
		//We may also check the number of players on this table
		return true;
	}
	
	//The player exit from a game
		public void exit(Player player){
			playersPresent.put(player, new Boolean(false));
		}
	/**
	 * This does not reset all the attributes to their default values .
	 * This is used when game on this table ends.
	 */
	public void gameOver(){
		iter=null;
		//Kick off all the shadow players(leave in game)
		ArrayList<Player > players=new ArrayList<Player>();
		synchronized (playerList) {
			for (Player p:playerList)
				if (onTable(p)) players.add(p);
			playerList=players;
			type=TableType.PRIVATE;
			if (playerList.size()==0) resetTable();
		}
		
	}
	
	/**
	 * This resets all the attributes to their default values .
	 * This is called when all players leave this table .
	 */
	public void resetTable(){
		moderator=null;
		/*String gameID=null;*/
		playerList=new ArrayList<Player>(); 
		invitationList=new ArrayList<Player>();
		seed=0;
		options=defaultOptions;
		game=null;
		type=TableType.PUBLIC;
		playersPresent=new Hashtable<Player,Boolean>();
		iter=null;
		
	}
	public String getGame() {
		return game;
	}
	public void setGame(String game) {
		this.game = game;
	}

	
	/**
	 * 

	 *
	 */
	public String toXML(){
		StringBuilder sb=new StringBuilder();
		sb.append("<table id=\"");
		sb.append(id);
		sb.append("\" seed=\"");
		sb.append(seed);
		sb.append("\" type=\"");
		sb.append(type.toString());
		sb.append("\" full=\"");
		sb.append(playerList.size()==numPlayers);
		sb.append("\" moderator=\"");
		if (moderator!=null)
			sb.append(moderator.getId());
		//This is meaningless. The client should first check the 
		//sequence of player-ids to determine if this table is empty
		else sb.append("1");
		sb.append("\" game=\"");
		if (game!=null)
			sb.append(game);
		sb.append("\" options=\"");
		if (options!=null)
			sb.append(options);
		
		sb.append("\">");
		
		//Get the rating of the given game
		synchronized (playerList){
		for (Player p:playerList){
			if (type==TableType.IN_PLAY){
			if (onTable(p))
				sb.append(p.toXMLPlayerID(game));
			}else sb.append(p.toXMLPlayerID(game));
		}
		}
		sb.append("</table>");
		return sb.toString();
	}
	
	
}
